package host.skiree.nettydemo.protocol;

import com.google.gson.*;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @author anorak
 */
public interface Serializ {

    /**
     * 序列化
     * @param object 对象
     * @return 字节数组
     * @param <T> 泛型
     */
    <T> byte[] serializ(T object);

    /**
     * 反序列化
     * @param clazz 类型
     * @param bytes 字节数组
     * @return 对象
     * @param <T> 泛型
     */
    <T> T deserializ(Class<T> clazz, byte[] bytes);


    /**
     * 序列化以及反序列化方式 Java, Json
     */
    enum Type implements Serializ {

        Java{
            @Override
            public <T> byte[] serializ(T object) {
                try {
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    new ObjectOutputStream(out).writeObject(object);
                    return out.toByteArray();
                } catch (IOException e) {
                    throw new RuntimeException("SerializerAlgorithm.Java 序列化错误", e);
                }
            }

            @Override
            public <T> T deserializ(Class<T> clazz, byte[] bytes) {
                try {
                    ObjectInputStream in =
                            new ObjectInputStream(new ByteArrayInputStream(bytes));
                    Object object = in.readObject();
                    return (T) object;
                } catch (IOException | ClassNotFoundException e) {
                    throw new RuntimeException("SerializerAlgorithm.Java 反序列化错误", e);
                }
            }
        },
        Json{
            @Override
            public <T> byte[] serializ(T object) {
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new ClassCodec()).create();
                String json = gson.toJson(object);
                return json.getBytes(StandardCharsets.UTF_8);
            }

            /**
             * Json类型的数据 的反序列化 类型 必须具体指定,不能使用Message.class
             * @param clazz 类型
             * @param bytes 字节数组
             * @return
             * @param <T>
             */
            @Override
            public <T> T deserializ(Class<T> clazz, byte[] bytes) {
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new ClassCodec()).create();
                String json = new String(bytes, StandardCharsets.UTF_8);
                return gson.fromJson(json,clazz);
            }
        }
    }

    /**
     * Json序列化我们使用了Gson来实现,Gson在对Class和String转换时有问题，我们需要实现以下接口来解决问题
     */
    class ClassCodec implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
        @Override
        public Class<?> deserialize(JsonElement json, java.lang.reflect.Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            try {
                return Class.forName(json.getAsString());
            } catch (ClassNotFoundException e) {
                throw new JsonParseException(e);
            }
        }

        @Override
        public JsonElement serialize(Class<?> src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) {
            return new JsonPrimitive(src.getName());
        }
    }

}
